package com.chat.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.chat.entry.dto.user.*;
import com.chat.entry.enums.GenderEnum;
import com.chat.entry.po.User;
import com.chat.entry.vo.user.LoginVO;
import com.chat.mapper.UserMapper;
import com.chat.result.Result;
import com.chat.service.IUserService;
import com.chat.utils.JwtUtil;
import com.chat.utils.VerifyUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.codec.binary.Base64;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author author
 * @since 2025-08-10
 */
@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private UserMapper userMapper;

    private final static String PHONE_CODE = "123456";

    @Override
    public Result generateVerificationCode() {
        // 生成图像验证码
        Object[] code = VerifyUtil.newBuilder().setWidth(120)  //设置图片的宽度
                .setHeight(50)  //设置图片的高度
                .setSize(6)     //设置字符的个数
                .setLines(3)    //设置干扰线的个数
                .setFontSize(20)//设置字体的大小
                .setTilt(false)  //设置图片是否倾斜
                .setBackgroundColor(Color.LIGHT_GRAY)   //设置图片的背景颜色
                .build()        //构建VerifyUtil项目
                .createImage(); //创建图片

        // 生成图片验证码的校验码
        String verifyCode = code[0].toString();
        log.info("图像验证码：{}", verifyCode);
        // 存入到缓存中，实现1分钟自动失效
        redisTemplate.opsForValue().set("image-code", verifyCode, 5, TimeUnit.MINUTES);
        // 将图片输出的到浏览器上
        BufferedImage image = (BufferedImage) code[1];
        return Result.success("", bufferedImageToBase64(image));
    }

    /**
     * BufferedImage 转 base64
     *
     * @param bufferedImage
     * @return
     */
    public String bufferedImageToBase64(BufferedImage bufferedImage) {
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        try {
            ImageIO.write(bufferedImage, "png", stream);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        byte[] bytes = Base64.encodeBase64(stream.toByteArray());
        String string = new String(bytes);
        return "data:image/png;base64," + string;
    }

    @Override
    public Result sendVerificationCode(String phoneNumber, String imageCode) {
        if (VerifyUtil.isPhoneNumber(phoneNumber)) {
            return Result.error("手机号格式不标准!");
        }
        log.info("图像验证码：{}", imageCode);
        if (!imageCode.equals(redisTemplate.opsForValue().get("image-code"))) {
            return Result.error("图像验证码不正确!");
        }
        Map<String, String> map = new HashMap<>();
        map.put("phoneCode", "123456");
        return Result.success("", map);
    }

    @Override
    public Result register(UserRegisterDTO userRegisterDTO, String phoneCode) {
        // 判断手机号是否已经被注册
        User getByPhone = getOne(new LambdaQueryWrapper<User>()
                .eq(User::getPhone, userRegisterDTO.getPhone()));
        if (getByPhone != null) {
            return Result.error("该手机号已注册！");
        }

        // 判断用户账号是否已经被注册
        User getByUserName = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getUsername, userRegisterDTO.getUsername()));
        if (getByUserName != null) {
            return Result.error("该用户号已注册！");
        }

        if (phoneCode.equals(PHONE_CODE)) {
            User user = User.builder().intro("他(她)还未进行自我介绍哦")
                    .avator("default")
                    .gender(GenderEnum.MAN)
                    .age(0)
                    .phoneVerity(1)
                    .completeInformation(0)
                    .createTime(LocalDateTime.now())
                    .updateTime(LocalDateTime.now())
                    .build();
            BeanUtils.copyProperties(userRegisterDTO, user);
            user.setPassword(DigestUtils.md5DigestAsHex(userRegisterDTO.getPassword().getBytes()));
            userMapper.insert(user);
            return Result.success("账号注册成功", null);
        } else {
            return Result.error("手机验证码不正确");
        }
    }

    @Override
    public Result login(UserRegisterDTO userRegisterDTO) {
        String username = userRegisterDTO.getUsername();
        String password = userRegisterDTO.getPassword();

        User user = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getUsername, username));

        if (user == null) {
            return Result.error("请先注册账号");
        }

        if (!user.getPassword().equals(DigestUtils.md5DigestAsHex(password.getBytes()))) {
            return Result.error("密码不正确");
        }

        String accessToken = JwtUtil.generateAccessToken(user.getUid(), username);
        String refreshToken = JwtUtil.generateRefreshToken(user.getUid(), username);

        return Result.success("登陆成功", new LoginVO(user, accessToken, refreshToken));
    }

    @Override
    public Result phoneLogin(PhoneLoginDTO phoneLoginDTO) {
        // TODO 验证码手机验证码
        if (!phoneLoginDTO.getPhoneCode().equals("123456")) {
            return Result.error("手机验证码不正确");
        }

        User user = getOne(new LambdaQueryWrapper<User>().eq(User::getPhone, phoneLoginDTO.getPhoneNumber()));

        if (user == null) {
            return Result.error("手机号未被注册");
        }

        String username = user.getUsername();
        String accessToken = JwtUtil.generateAccessToken(user.getUid(), username);
        String refreshToken = JwtUtil.generateRefreshToken(user.getUid(), username);

        return Result.success("登陆成功", new LoginVO(user, accessToken, refreshToken));
    }

    @Override
    public Result updateUsername(Integer uid, UpdateUsernameDTO updateUsernameDTO) {
        User user = getById(uid);
        String username = user.getUsername();

        String oldUsername = updateUsernameDTO.getOldUsername();
        String newUsername = updateUsernameDTO.getNewUsername();

        if (!username.equals(oldUsername)) {
            return Result.error("旧用户名不正确");
        }

        if (oldUsername.equals(newUsername)) {
            return Result.error("新用户名不能和旧用户名相同");
        }

        User getByUsername = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getUsername, newUsername));
        if (getByUsername != null) {
            return Result.error("用户名已被使用");
        }

        user.setUsername(newUsername);
        updateById(user);

        // 修改用户号之后会刷新token 刷新token
        Map<String, Object> claims = new HashMap<>();
        claims.put("uid", user.getUid());
        claims.put("username", user.getUsername());
        claims.put("password", DigestUtils.md5DigestAsHex(user.getPassword().getBytes()));

        String accessToken = JwtUtil.generateAccessToken(user.getUid(), user.getUsername());
        String refreshToken = JwtUtil.generateRefreshToken(user.getUid(), user.getUsername());

        return Result.success("修改成功", new LoginVO(user, accessToken, refreshToken));
    }

    @Override
    public Result updateIntro(Integer uid, UpdateIntroDTO updateIntroDTO) {
        String intro = updateIntroDTO.getIntro();
        int introLength = intro.length();

        if (introLength >= 255) {
            return Result.error("简介太多了，可以简化一下");
        }

        User user = getById(uid).setIntro(intro);
        updateById(user);
        return Result.success("修改成功", null);
    }

    @Override
    public Result updatePassword(Integer uid, UpdatePasswordDTO updatePasswordDTO) {
        User user = getById(uid);

        String oldPassword = updatePasswordDTO.getOldPassword();
        String newPassword = updatePasswordDTO.getNewPassword();

        if (!user.getPassword().equals(DigestUtils.md5DigestAsHex(oldPassword.getBytes()))) {
            return Result.error("请输入正确的旧密码");
        }

        user.setPassword(DigestUtils.md5DigestAsHex(newPassword.getBytes()));
        updateById(user);

        // 修改密码之后会刷新token 刷新token
        Map<String, Object> claims = new HashMap<>();
        claims.put("uid", user.getUid());
        claims.put("username", user.getUsername());
        claims.put("password", DigestUtils.md5DigestAsHex(user.getPassword().getBytes()));

        String accessToken = JwtUtil.generateAccessToken(user.getUid(), user.getUsername());
        String refreshToken = JwtUtil.generateRefreshToken(user.getUid(), user.getUsername());

        return Result.success("修改成功", new LoginVO(user, accessToken, refreshToken));
    }

    @Override
    public Result updateComplete(Integer uid, UpdateUserCompleteDTO updateUserCompleteDTO) {
        User user = getById(uid);
        if (user == null) {
            return Result.error("用户不存在");
        }

        BeanUtils.copyProperties(updateUserCompleteDTO, user);

        boolean update = updateById(user);

        if (update) {
            return Result.success("修改成功", null);
        } else {
            return Result.error("无任何修改");
        }
    }

    @Override
    public Result getUser(Integer userId) {
        return Result.success("查询成功", getOne(new LambdaQueryWrapper<User>().eq(User::getUid, userId)));
    }

    public Result forgetPassword(String phoneNumber, String password) {
        // 1. 查询用户是否存在
        User user = getOne(new LambdaQueryWrapper<User>().eq(User::getPhone, phoneNumber));
        if (user == null) {
            return Result.error("用户不存在");
        }

        // 2. 加密密码（这里用 MD5，但推荐使用更安全的 BCrypt）
        String md5Password = DigestUtils.md5DigestAsHex(password.getBytes());

        // 3. 更新密码
        boolean success = update(new LambdaUpdateWrapper<User>()
                .eq(User::getPhone, phoneNumber)
                .set(User::getPassword, md5Password));

        // 4. 返回结果
        if (success) {
            return Result.success("密码修改成功", null);
        } else {
            return Result.error("密码修改失败");
        }
    }


    @Override
    public Result sendPhoneCode(String phoneNumber) {
        if (VerifyUtil.isPhoneNumber(phoneNumber)) {
            return Result.error("手机号格式不标准!");
        }
        Map<String, String> map = new HashMap<>();
        map.put("phoneCode", "123456");
        return Result.success("发送成功", map);
    }

}
